const letterMapNumber = {
  '0': 0,
  '1': 1,
  '2': 2,
  '3': 3,
  '4': 4,
  '5': 5,
  '6': 6,
  '7': 7,
  '8': 8,
  '9': 9,
  'a': 10,
  'b': 11,
  'c': 12,
  'd': 13,
  'e': 14,
  'f': 15,
  'A': 10,
  'B': 11,
  'C': 12,
  'D': 13,
  'E': 14,
  'F': 15,
}

const BITLENGTH = 64 // 2进制 长度
const HEXLENGTH = BITLENGTH / 4 //16进制 长度 

/**
 * 16 进制明文，转 二进制
 * @param str 
 * @returns 
 */
export function getBinary(str: string) {
  const arr = []
  for (let i = 0; i < str.length; i += 2) {
    const value = str.substring(i, i + 2)
    arr.push(parseInt('0x' + value))
  }
  const uint8Arr = new Uint8Array(arr)
  const M = Buffer.concat([uint8Arr])
  const MBinary = HexToBinary(M)
  return MBinary
}

/**
 * 获取明文 16 进制数
 * @param text 明文内容
 * @returns Buffer
 */
export function getBuffer(text: string) {
  let buffer = Buffer.from(text) /* Buffer.from 返回的是 16进制数 */

  const surplus = buffer.length % (HEXLENGTH / 2)
  if (surplus !== 0) {
    const shortNum = (HEXLENGTH / 2) - surplus
    // 补 0
    const zeros = Buffer.alloc(shortNum)
    buffer = Buffer.concat([buffer, zeros], buffer.length + zeros.length)
  }
  return buffer
}

/**
 * Buffer数据 16进制 转 2 进制
 */
export function HexToBinary(data: Buffer) {
  // <Buffer 01 23 45 67 89 ab cd ef>
  let hexResult = ''
  /*
  由于数据在 Buffer 中是 16进制，但单个输出时是10进制，
  所以需要把 Buffer 中的数据转化为16进制表示的字符串，在进行2进制转换
   */
  data.forEach(item => {
    // 转为 16进制 字符串
    hexResult += to16(item)
  })

  let binaryResult = ''
  for (let i = 0; i < hexResult.length; i++) {
    const value = hexResult[i]
    // @ts-ignore
    const number = letterMapNumber[value];
    let binary = to2(number)

    binaryResult += binary
  }
  return binaryResult
}

/**
 * 10 进制转 16进制 
 * @param num 数字
 * @param splice 因为 Buffer 数据的每一位是2个16进制的字符，所以这两个字符转为10进制后，再转回16进制的话，就需分别算出第一个，第二个，再拼接在一起
 * 而最终的加密结果，是 4bit（4个二进制） 数，意味着是一个16进制数，所以不需要进行拼接。
 * @returns 
 */
export function to16(num: number, splice = true) {
  const mapTable = ['a', 'b', 'c', 'd', 'e', 'f']

  let one: number = Math.floor(num / 16)
  const one_s: string = one > 9 ? mapTable[one % 10] : one + ''

  let two: number = num % 16
  const two_s: string = two > 9 ? mapTable[two % 10] : two + ''

  const result = splice ? one_s + two_s : two_s

  return result
}

/**
 * 4位 2进制转10进制，e.g: 1000 => 8
 * @param str 
 * @returns 
 */
export function to10(str: string) {
  const zeros = '0000'
  const shortNum = 4 - str.length
  str = zeros.substring(0, shortNum) + str
  let number = 0
  for (let i = 0; i < str.length; i++) {
    const value = str.substring(i, i + 1)
    if (value === '1') {
      if (i !== str.length - 1) {
        // 3 - [0, 1, 2] = [3,2,1]
        number += 2 ** ((str.length - 1) - i)

      } else {
        number += 1
        // console.log(number);
      }
    }
  }

  return number
}

/**
 * 2进制串 转 16 进制
 * @param binary 
 * @returns 
 */
export function binaryToHex(binary: string) {

  let s = ''
  // 2 转 10 
  for (let i = 0; i < binary.length / 4; i++) {
    const item = binary.substring(i * 4, i * 4 + 4)
    s += to16(to10(item), false)
  }
  return s
}

/**
 * 
 * @param num 
 * @returns 
 */
function DecimalTransformBinary(num: number): string {
  if (num === 0 || num === 1) return num + ''
  // 余数
  const remainder = num % 2 + ''
  const result = Math.floor(num / 2)

  return DecimalTransformBinary(result) + remainder
}

/**
 * 一个 10 进制 转 2进制
 * @param num 
 * @returns 
 */
export function to2(num: number) {
  let result = DecimalTransformBinary(num)
  const zeros = '0000'
  const shortNum = 4 - result.length
  result = zeros.substring(0, shortNum) + result
  return result
}

/**
 * 置换
 * @param binary 二进制字符串 
 * @param table 置换表
 * @returns 
 */
export function permutation(binary: string, table: number[]) {
  let s: string = ''
  table.forEach(n => {
    let value = binary.substring(n - 1, n)
    s += value
  })

  return s
}